package generator

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"x-admin-generator/internal/config"
	"x-admin-generator/internal/types"
)

// GenerateModel 生成模型
func GenerateModel(modelName string) {
	// 读取模型配置
	configPath := config.GetConfigPath(fmt.Sprintf("%s.yaml", strings.ToLower(modelName)))
	modelConfig, err := config.LoadModelConfig(configPath)
	if err != nil {
		log.Fatalf("加载模型配置失败: %v", err)
	}

	// 清理并创建临时目录
	if err := SetupTempDirectory(); err != nil {
		log.Fatalf("设置临时目录失败: %v", err)
	}

	// 准备模板数据
	data := prepareTemplateData(modelConfig)

	// 生成后端代码
	GenerateBackendFiles(data)

	// 生成前端代码
	GenerateFrontendFiles(data)

	fmt.Printf("✅ 模型 %s 的CRUD代码生成完成!\n", modelName)
	fmt.Printf("📁 生成的文件位于: %s\n", config.GetTempDir())
	fmt.Println("💡 请检查生成的代码，确认无误后复制到项目目录")
}

// GenerateAllModels 生成所有模型
func GenerateAllModels() {
	cfg := config.GetConfig()
	configDir := cfg.Paths.ModelsConfig
	files, err := filepath.Glob(filepath.Join(configDir, "*.yaml"))
	if err != nil {
		log.Fatalf("读取配置目录失败: %v", err)
	}

	if len(files) == 0 {
		fmt.Printf("在 %s 目录下没有找到模型配置文件\n", configDir)
		return
	}

	// 清理并创建临时目录（只需要一次）
	if err := SetupTempDirectory(); err != nil {
		log.Fatalf("设置临时目录失败: %v", err)
	}

	for _, file := range files {
		modelName := strings.TrimSuffix(filepath.Base(file), ".yaml")
		modelName = strings.Title(modelName)
		fmt.Printf("生成模型: %s\n", modelName)
		GenerateModelToTemp(modelName)
	}

	fmt.Printf("\n✅ 所有模型的CRUD代码生成完成!\n")
	fmt.Printf("📁 生成的文件位于: %s\n", config.GetTempDir())
	fmt.Println("💡 请检查生成的代码，确认无误后复制到项目目录")
}

// GenerateModelToTemp 生成模型到临时目录（不清理目录）
func GenerateModelToTemp(modelName string) {
	// 读取模型配置
	configPath := config.GetConfigPath(fmt.Sprintf("%s.yaml", strings.ToLower(modelName)))
	modelConfig, err := config.LoadModelConfig(configPath)
	if err != nil {
		log.Printf("加载模型配置失败 %s: %v", modelName, err)
		return
	}

	// 准备模板数据
	data := prepareTemplateData(modelConfig)

	// 生成后端代码
	GenerateBackendFiles(data)

	// 生成前端代码
	GenerateFrontendFiles(data)
}

// prepareTemplateData 准备模板数据
func prepareTemplateData(modelConfig *types.ModelConfig) types.TemplateData {
	modelNameCamel := config.ToCamelCase(modelConfig.Model.Name)
	modelNameSnake := config.ToSnakeCase(modelConfig.Model.Name)
	modulePath := config.GetModulePath()

	return types.TemplateData{
		ModelName:      modelConfig.Model.Name,
		ModelNameCamel: modelNameCamel,
		ModelNameSnake: modelNameSnake,
		TableName:      modelConfig.Model.Table,
		Comment:        modelConfig.Model.Comment,
		Fields:         modelConfig.Model.Fields,
		PackageName:    strings.ToLower(modelConfig.Model.Name),
		LowerName:      strings.ToLower(modelConfig.Model.Name),
		ModulePath:     modulePath,
	}
}

// SetupTempDirectory 设置临时目录
func SetupTempDirectory() error {
	tempDir := config.GetTempDir()
	// 如果临时目录存在，先删除
	if _, err := os.Stat(tempDir); err == nil {
		fmt.Printf("🧹 清理临时目录: %s\n", tempDir)
		if err := os.RemoveAll(tempDir); err != nil {
			return fmt.Errorf("删除临时目录失败: %w", err)
		}
	}

	// 创建新的临时目录
	fmt.Printf("📁 创建临时目录: %s\n", tempDir)
	if err := os.MkdirAll(tempDir, 0755); err != nil {
		return fmt.Errorf("创建临时目录失败: %w", err)
	}

	// 创建子目录结构（模块化）
	dirs := []string{
		filepath.Join(tempDir, "backend", "internal", "modules"),
	}

	for _, dir := range dirs {
		if err := os.MkdirAll(dir, 0755); err != nil {
			return fmt.Errorf("创建目录失败 %s: %w", dir, err)
		}
	}

	return nil
}

// GenerateBackendFiles 生成后端文件
func GenerateBackendFiles(data types.TemplateData) {
	// 模块化生成：每个功能一个包
	moduleDir := filepath.Join(config.GetTempDir(), "backend", "internal", "modules", data.LowerName)

	templates := map[string]string{
		"templates/backend/module/model.tmpl":      filepath.Join(moduleDir, "model.go"),
		"templates/backend/module/repository.tmpl": filepath.Join(moduleDir, "repository.go"),
		"templates/backend/module/service.tmpl":    filepath.Join(moduleDir, "service.go"),
		"templates/backend/module/handler.tmpl":    filepath.Join(moduleDir, "handler.go"),
		"templates/backend/module/router.tmpl":     filepath.Join(moduleDir, "router.go"),
	}

	for templatePath, outputPath := range templates {
		if err := GenerateFromTemplate(templatePath, outputPath, data); err != nil {
			log.Printf("生成后端文件失败 %s: %v", outputPath, err)
		} else {
			fmt.Printf("✓ 生成后端文件: %s\n", outputPath)
		}
	}

	// 生成使用说明
	GenerateModuleUsageInstructions(data)

	// 更新自动路由注册文件
	UpdateAutoRouterFiles()
}

// GenerateFrontendFiles 生成前端文件
func GenerateFrontendFiles(data types.TemplateData) {
	// 创建模块目录
	moduleDir := filepath.Join(config.GetTempDir(), "frontend", "src", "modules", data.LowerName)
	os.MkdirAll(moduleDir, 0755)

	templates := map[string]string{
		"templates/frontend/list.vue.tmpl": filepath.Join(moduleDir, "list.vue"),
		"templates/frontend/form.vue.tmpl": filepath.Join(moduleDir, "form.vue"),
		"templates/frontend/api.js.tmpl":   filepath.Join(moduleDir, "api.js"),
	}

	for templatePath, outputPath := range templates {
		if err := GenerateFromTemplate(templatePath, outputPath, data); err != nil {
			log.Printf("生成前端文件失败 %s: %v", outputPath, err)
		} else {
			fmt.Printf("✓ 生成前端文件: %s\n", outputPath)
		}
	}
}

// GenerateFromTemplate 从模板生成文件
func GenerateFromTemplate(templatePath, outputPath string, data types.TemplateData) error {
	// 读取模板文件
	templateContent, err := os.ReadFile(templatePath)
	if err != nil {
		return fmt.Errorf("读取模板文件失败: %w", err)
	}

	// 创建模板函数映射
	funcMap := template.FuncMap{
		"title": strings.Title,
		"lower": strings.ToLower,
		"upper": strings.ToUpper,
		"camel": config.ToCamelCase,
		"snake": config.ToSnakeCase,
	}

	// 解析模板
	tmpl, err := template.New("generator").Funcs(funcMap).Parse(string(templateContent))
	if err != nil {
		return fmt.Errorf("解析模板失败: %w", err)
	}

	// 创建输出目录
	outputDir := filepath.Dir(outputPath)
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		return fmt.Errorf("创建输出目录失败: %w", err)
	}

	// 创建输出文件
	outputFile, err := os.Create(outputPath)
	if err != nil {
		return fmt.Errorf("创建输出文件失败: %w", err)
	}
	defer outputFile.Close()

	// 执行模板
	if err := tmpl.Execute(outputFile, data); err != nil {
		return fmt.Errorf("执行模板失败: %w", err)
	}

	return nil
}

// GenerateModuleUsageInstructions 生成模块使用说明
func GenerateModuleUsageInstructions(data types.TemplateData) {
	instructions := fmt.Sprintf(`# %s 模块使用说明

## 📁 生成的文件结构
`+"`"+`
backend/internal/modules/%s/
├── model.go       # 数据模型和请求结构体
├── repository.go  # 数据访问层
├── service.go     # 业务逻辑层
├── handler.go     # HTTP处理器
└── router.go      # 路由注册

frontend/src/modules/%s/
├── api.js         # API接口
├── list.vue       # 列表页面
└── form.vue       # 表单页面
`+"`"+`

## 🔧 集成到项目

### 1. 复制后端模块文件
将生成的 backend/internal/modules/%s 目录复制到项目的 backend/internal/modules/ 目录下

### 2. 复制前端模块文件
将生成的 frontend/src/modules/%s 目录复制到项目的 frontend/src/modules/ 目录下

### 3. 自动路由注册
模块已自动注册到路由系统，无需手动配置！

生成的自动路由文件：
- auto_router.go - 自动路由注册器
- registry.go - 模块注册表
- init.go - 路由初始化函数
- auto_routes.js - 前端自动路由配置

只需在您的 main.go 中调用：
`+"`"+`go
router.InitializeRoutes(r, db)
`+"`"+`

### 4. 数据库迁移
确保数据库中存在对应的表 %s，或者在数据库迁移中添加表结构。

## 🎯 API接口

生成的模块提供以下REST API接口：

- GET    /%s      - 获取%s列表（支持分页和搜索）
- GET    /%s/:id  - 获取%s详情
- POST   /%s      - 创建%s
- PUT    /%s/:id  - 更新%s
- DELETE /%s/:id  - 删除%s

## 📝 自定义修改

生成的代码是基础模板，您可以根据业务需求进行以下自定义：

1. **模型字段**：在 model.go 中调整字段定义和验证规则
2. **业务逻辑**：在 service.go 中添加自定义业务逻辑
3. **查询条件**：在 repository.go 中调整查询和筛选逻辑
4. **API响应**：在 handler.go 中自定义响应格式
5. **路由权限**：在 router.go 中添加权限中间件

## ⚠️ 注意事项

1. 确保项目中已安装所需依赖包
2. 检查生成的代码是否与现有代码风格一致
3. 根据实际业务需求调整字段验证规则
4. 添加适当的错误处理和日志记录
`, data.Comment, data.LowerName, data.LowerName, data.LowerName, data.LowerName, data.TableName, data.LowerName, data.Comment, data.LowerName, data.Comment, data.LowerName, data.Comment, data.LowerName, data.Comment, data.LowerName, data.Comment)

	instructionPath := filepath.Join(config.GetTempDir(), "backend", "internal", "modules", data.LowerName, fmt.Sprintf("%s_module_usage.md", data.LowerName))
	if err := os.WriteFile(instructionPath, []byte(instructions), 0644); err != nil {
		log.Printf("生成使用说明失败: %v", err)
	} else {
		fmt.Printf("✓ 生成使用说明: %s\n", instructionPath)
	}
}

// UpdateAutoRouterFiles 更新自动路由注册文件
func UpdateAutoRouterFiles() {
	// 扫描所有已生成的模块
	modules := scanGeneratedModules()

	// 生成后端自动路由文件
	generateBackendAutoRouter(modules)

	// 生成前端自动路由文件
	generateFrontendAutoRouter(modules)
}

// scanGeneratedModules 扫描已生成的模块
func scanGeneratedModules() []types.ModuleInfo {
	var modules []types.ModuleInfo

	// 扫描临时目录中的模块
	tempModulesDir := filepath.Join(config.GetTempDir(), "backend", "internal", "modules")
	if entries, err := os.ReadDir(tempModulesDir); err == nil {
		for _, entry := range entries {
			if entry.IsDir() {
				moduleName := entry.Name()

				// 尝试读取模块配置
				configPath := config.GetConfigPath(fmt.Sprintf("%s.yaml", moduleName))
				if modelConfig, err := config.LoadModelConfig(configPath); err == nil {
					modules = append(modules, types.ModuleInfo{
						Name:      modelConfig.Model.Name,
						LowerName: strings.ToLower(modelConfig.Model.Name),
						TableName: modelConfig.Model.Table,
						Comment:   modelConfig.Model.Comment,
					})
				}
			}
		}
	}

	return modules
}

// generateBackendAutoRouter 更新后端模块注册表
func generateBackendAutoRouter(modules []types.ModuleInfo) {
	cfg := config.GetConfig()
	modulePath := cfg.Generation.PackagePrefix

	// 更新项目中的模块注册表文件
	registryPath := "../backend/internal/modules/registry.go"
	registryData := struct {
		ModulePath string
		Modules    []string
	}{
		ModulePath: modulePath,
		Modules:    make([]string, len(modules)),
	}

	for i, module := range modules {
		registryData.Modules[i] = module.LowerName
	}

	if err := generateFromTemplateGeneric("templates/backend/module_registry.go.tmpl", registryPath, registryData); err != nil {
		log.Printf("更新模块注册表失败: %v", err)
	} else {
		fmt.Printf("✓ 更新模块注册表: %s\n", registryPath)
	}
}

// generateFrontendAutoRouter 生成前端自动路由文件
func generateFrontendAutoRouter(modules []types.ModuleInfo) {
	// 更新项目中的前端自动路由文件
	autoRoutesPath := "../frontend/src/router/auto_routes.js"

	routesData := struct {
		Modules []types.ModuleInfo
	}{
		Modules: modules,
	}

	if err := generateFromTemplateGeneric("templates/frontend/auto_routes.js.tmpl", autoRoutesPath, routesData); err != nil {
		log.Printf("更新前端自动路由失败: %v", err)
	} else {
		fmt.Printf("✓ 更新前端自动路由: %s\n", autoRoutesPath)
	}
}

// generateFromTemplateGeneric 通用模板生成函数
func generateFromTemplateGeneric(templatePath, outputPath string, data interface{}) error {
	// 读取模板文件
	templateContent, err := os.ReadFile(templatePath)
	if err != nil {
		return fmt.Errorf("读取模板文件失败: %w", err)
	}

	// 创建模板函数映射
	funcMap := template.FuncMap{
		"title": strings.Title,
		"lower": strings.ToLower,
		"upper": strings.ToUpper,
		"camel": config.ToCamelCase,
		"snake": config.ToSnakeCase,
	}

	// 解析模板
	tmpl, err := template.New("generator").Funcs(funcMap).Parse(string(templateContent))
	if err != nil {
		return fmt.Errorf("解析模板失败: %w", err)
	}

	// 创建输出目录
	outputDir := filepath.Dir(outputPath)
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		return fmt.Errorf("创建输出目录失败: %w", err)
	}

	// 创建输出文件
	outputFile, err := os.Create(outputPath)
	if err != nil {
		return fmt.Errorf("创建输出文件失败: %w", err)
	}
	defer outputFile.Close()

	// 执行模板
	if err := tmpl.Execute(outputFile, data); err != nil {
		return fmt.Errorf("执行模板失败: %w", err)
	}

	return nil
}

// CopyFile 复制单个文件
func CopyFile(src, dst string) error {
	sourceFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sourceFile.Close()

	destFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer destFile.Close()

	_, err = io.Copy(destFile, sourceFile)
	if err != nil {
		return err
	}

	// 复制文件权限
	sourceInfo, err := os.Stat(src)
	if err != nil {
		return err
	}

	return os.Chmod(dst, sourceInfo.Mode())
}